#ifndef BUILTIN_H
#define BUILTIN_H
#include "types.h"

// Scope functions
value_t *builtin_def(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);

value_t *builtin_scope(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);
value_t *builtin_hide(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);

value_t *builtin_load(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);
value_t *builtin_use(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);

value_t *builtin_let(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);

// Control Flow functions

value_t *builtin_if(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);
value_t *builtin_apply(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);
value_t *builtin_match(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);

value_t *builtin_try(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);
value_t *builtin_throw(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);
value_t *builtin_catch(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);

// Type functions
value_t *builtin_type(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);
value_t *builtin_arity(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);
value_t *builtin_varargs(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);

// Comparison functions

value_t *builtin_lt(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);
value_t *builtin_lte(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);
value_t *builtin_gt(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);
value_t *builtin_gte(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);
value_t *builtin_eq(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);
value_t *builtin_neq(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);

// Arithmetic functions

value_t *builtin_add(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);
value_t *builtin_subtract(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);
value_t *builtin_multiply(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);
value_t *builtin_divide(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);
value_t *builtin_mod(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);
/*truncating division */
value_t *builtin_div(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);

// List functions
value_t *builtin_head(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);
value_t *builtin_tail(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);
value_t *builtin_length(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);

// Reference functions
value_t *builtin_set(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);
value_t *builtin_get(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);
value_t *builtin_reference(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);

// I/O functions (should these be palmed off to the FFI later?)
value_t *builtin_input(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);
value_t *builtin_print(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);
value_t *builtin_show(generic_list_t *arguments, scope_t *scope, int tail, handler_t *handler);

// FFI functions

/*See notes from Winchester train */

scope_t *construct_builtins();

#endif // BUILTIN_H
